#include "EventDispatcher.hpp"
#include "util/Log.hpp"
#include "Select.hpp"
#include "Event.hpp"
#include <algorithm>

#include "pthread/ScopedLock.hpp"

int EventDispatcher::getMaxFileDiscriptor() {
	int result = -1;
	for (unsigned int i = 0; i < tasks.size(); i++) {
		result = std::max(tasks[i]->getFileDiscriptor(), result);
	}
	return result + 1;
}

void EventDispatcher::addTask(Task * task) {
	ScopedLock lock(mutex);
	addTaskQueue.push_back(task);

}
void EventDispatcher::removeTask(Task * task) {
	ScopedLock lock(mutex);
	removeTaskQueue.push_back(task);

}
//#include <fcntl.h>
void EventDispatcher::doAdd() {
	for (std::vector<Task *>::iterator it = addTaskQueue.begin();
			it != addTaskQueue.end(); ++it) {
		//	fcntl((*it)->getFileDiscriptor(), F_SETFL, O_NONBLOCK);
		tasks.push_back(*it);
		Context context(this, *it);
		try {
			(*it)->onInit(context);
		} catch (std::exception & e) {
			Log::v(
					"[EventDispatcher] Exception on Task::onInit(); "
							+ std::string(e.what()));
			removeTask(*it);
		}
	}

	addTaskQueue.clear();
}

void EventDispatcher::doRemove() {
	for (std::vector<Task *>::iterator it = removeTaskQueue.begin();
			it != removeTaskQueue.end(); ++it) {
		selectEvent.getReadSet().clear((*it)->getFileDiscriptor());
		selectEvent.getWriteSet().clear((*it)->getFileDiscriptor());
		tasks.erase(std::find(tasks.begin(), tasks.end(), (*it)));

		Context context(this, *it);
		try {
			Log::v(
					"[EventDispatcher] CALL Task::onDestroy() ["
							+ StringUtils::toString((*it)->getFileDiscriptor())
							+ "]");
			(*it)->onDestroy(context);

		} catch (std::exception & e) {
			Log::v(
					"[EventDispatcher] Exception on Task::onDestroy(); "
							+ std::string(e.what()));
		}

		delete *it;

	}

	removeTaskQueue.clear();

}
#include <iostream>
#include <sys/socket.h>
int iter = 0;
void EventDispatcher::run() {

	while (true) {
		mutex.lock();
//		std::cerr<<"iter = "<<iter++<<std::endl;
		doRemove();

		doAdd();

		Event event(selectEvent);
		int maxFd = getMaxFileDiscriptor();
		mutex.unlock();
		Select::select(maxFd, event);
		mutex.lock();
		for (std::vector<Task *>::iterator it = tasks.begin();
				it != tasks.end(); ++it) {

			Context context(this, *it);
			if (event.getReadSet().isSet((*it)->getFileDiscriptor())) {

				try {
					(*it)->onRead(context);
				} catch (std::exception & e) {
					Log::v(
							"[EventDispatcher] Exception on Task::onRead(); "
									+ std::string(e.what()));
					removeTask((*it));
					break;
				}
			}

			if (event.getWriteSet().isSet((*it)->getFileDiscriptor())) {
				try {
					(*it)->onWrite(context);
				} catch (std::exception & e) {
					Log::v(
							"[EventDispatcher] Exception on Task::onWrite(); "
									+ std::string(e.what()));
					removeTask((*it));
					break;
				}
			}

		}
		mutex.unlock();
		if (tasks.empty()) {
			break;
		}
	}

}
